﻿
/* $Id: MainForm.cs 8 2011-03-31 22:17:59Z nramsbottom@gmail.com $ */

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;

namespace WinFormsClient
{
	public partial class MainForm : Form
	{
		private TcpClient _client;
		private BinaryReader _reader;
		private Thread _receiveThread;

		public MainForm()
		{
			InitializeComponent();
		} //

		private void btnConnect_Click(object sender, EventArgs e)
		{

			_client = new TcpClient();

			try
			{
				_client.Connect(IPAddress.Loopback, 1982);
			}
			catch (SocketException ex)
			{
				MessageBox.Show(this, "Unable to connect.", "Connect Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}

			if (_client.Connected)
			{
				_reader = new BinaryReader(_client.GetStream());
				_receiveThread = new Thread(ReceiveThreadProc);
				_receiveThread.Start();

				btnDisconnect.Enabled = true;
				btnConnect.Enabled = false;
				groupSendPacket.Enabled = true;
			}
			else
			{
				_client = null;
				btnDisconnect.Enabled = false;
				btnConnect.Enabled = true;
				groupSendPacket.Enabled = false;
			}

		}

		private void btnDisconnect_Click(object sender, EventArgs e)
		{
			if (_client != null)
			{
				_client.Close();
				_client = null;
			}

			btnDisconnect.Enabled = false;
			btnConnect.Enabled = true;
			groupSendPacket.Enabled = false;

		}

		private void btnSendLogin_Click(object sender, EventArgs e)
		{

			var username = txtUsername.TextLength > 32 ? txtUsername.Text.Substring(0, 32) : txtUsername.Text.PadRight(32);
			var password = txtPassword.TextLength > 32 ? txtPassword.Text.Substring(0, 32) : txtPassword.Text.PadRight(32);

			// of course, we wouldn't really send login details plain text
			var payload= System.Text.Encoding.ASCII.GetBytes(string.Format("{0}{1}", username, 
																																							 password));
			SendPacket(0x2, payload);


		} //

		private void btnSendNoOp_Click(object sender, EventArgs e)
		{
			SendPacket(0x1, null);
		} //


		private void SendPacket(UInt32 typeId, byte[] data)
		{
			try
			{
				var wtr = new BinaryWriter(_client.GetStream());
				wtr.Write(typeId);
				if (data != null)
					wtr.Write(data, 0, data.Length);
				wtr.Flush();
			}
			catch (IOException ex)
			{
				MessageBox.Show(this, "I/O error while trying to send packet.", "I/O Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
			catch (InvalidOperationException ex)
			{
				MessageBox.Show(this, "Operation failed.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}

		private void btnTest_Click(object sender, EventArgs e)
		{
			SendPacket(0x3, null);
		} //

		private void ReceiveThreadProc()
		{

			try
			{
				while (true)
				{

					var packetId = _reader.ReadUInt32();

					if (packetId == 0x80)
					{
						// login response
						var success = _reader.ReadByte() > 0;
						if (success)
							MessageBoxInfo("Logged in!", "Login");
						else
							MessageBoxError("Login failed.", "Login");
					}
					else if (packetId == 0x81)
					{
						// no-op response
						System.Diagnostics.Debug.WriteLine("NOOP - " + DateTime.Now.ToString());
					}
					else if (packetId == 0x82)
					{
						var msg = System.Text.Encoding.ASCII.GetString(_reader.ReadBytes(128)).Trim();
						System.Diagnostics.Debug.WriteLine("MOTD: " + msg);
						MessageBoxInfo(msg, "Server Greeting");
					}
					else if (packetId == 0x83)
					{
						var success = _reader.ReadBoolean();
						var msg = System.Text.Encoding.ASCII.GetString(_reader.ReadBytes(128)).Trim();

						if (!success)
							MessageBoxError("Command Failed: " + msg, "Server Command");
						else
							MessageBoxInfo("Command Success: " + msg, "Server Command");
					}

				}
			}
			catch (IOException ex)
			{
				ResetUI();

				if (ex.InnerException != null && ex.InnerException is SocketException)
				{
					switch (((SocketException)ex.InnerException).ErrorCode)
					{
						case 10004: // WSABlockingCall Cancelled (not an error)
							return;
					}
				}

				MessageBoxError("IO Exception.", "Error");
			}

		} //

		private void btnMotd_Click(object sender, EventArgs e)
		{
			SendPacket(0x4, null);
		} //

		private void btnCommand_Click(object sender, EventArgs e)
		{
			SendPacket(0x5, System.Text.Encoding.ASCII.GetBytes(txtCommand.Text.PadRight(32)));
		}

		private delegate void MessageBoxDelegate(string caption, string title);
		private void MessageBoxError(string caption, string title)
		{
			if (this.InvokeRequired)
				this.Invoke(new MessageBoxDelegate(MessageBoxError), caption, title);
			else
				MessageBox.Show(this, caption, title, MessageBoxButtons.OK, MessageBoxIcon.Error);
		} //

		private void MessageBoxInfo(string caption, string title)
		{
			if (this.InvokeRequired)
				this.Invoke(new MessageBoxDelegate(MessageBoxInfo), caption, title);
			else
				MessageBox.Show(this, caption, title, MessageBoxButtons.OK, MessageBoxIcon.Information);
		} //


		private delegate void VoidMethodDelegate();
		private void ResetUI()
		{
			if (this.InvokeRequired)
				this.Invoke(new VoidMethodDelegate(ResetUI));
			else
			{
				btnDisconnect.Enabled = false;
				btnConnect.Enabled = true;
				groupSendPacket.Enabled = false;
				_client = null;
			}
		}

		private void MainForm_Load(object sender, EventArgs e)
		{

		}

	} // class
} // namespace
